#include "contact.h"
int check_capacity(pContact p)
{
    /*
        检查通讯录容量是否超出，如果超出则进行扩容，并转移数据
        void *realloc(void *ptr, size_t size);
        功能：
        重新分配用malloc或者calloc函数在堆中分配内存空间的大小。
        realloc不会自动清理增加的内存，需要手动清理，如果指定的地址后面有连续的空间，那么就会在已有地址基础上增加内存，如果指定的地址后面没有空间，那么realloc会重新分配新的连续内存，把旧内存的值拷贝到新内存，同时释放旧内存。
        参数：
        ptr：为之前用malloc或者calloc分配的内存地址，如果此参数等于NULL，那么和realloc与malloc功能一致
        size：为重新分配内存的大小, 单位：字节
        返回值：
        成功：新分配的堆内存地址
        失败：NULL
    */
    if (p->sz == p->capacity)
    {
        //重新开辟内存
        PeoInfo *tmp = realloc(p->data, (p->capacity + DEFAULT_INC) * sizeof(PeoInfo));
        if (tmp != NULL) //容量扩展成功，
        {
            p->data = tmp;
            p->capacity += DEFAULT_INC;
        }
        else
            return 0;
    }
    return 1;
}
void InitContact(pContact p)
{
    /*
        初始化通讯录结构体
            为data分配内存
            初始化通讯录大小
            初始化通讯录容量
    */
    assert(p != NULL);
    p->data = (PeoInfo *)malloc(DEFAULT_SZ * sizeof(PeoInfo));
    if (p->data == NULL)
    {
        perror("InitContact:malloc");
        exit(-1);
    }
    memset(p->data, 0, DEFAULT_SZ * sizeof(PeoInfo)); //给p->data赋值
    p->sz = 0;                                        // 初始化大小为０
    p->capacity = DEFAULT_SZ;                         // 通讯录默认容量为１
    LoadContact(p);
}
void LoadContact(pContact p)
{
    /*
    从文件中导入通讯录
        通讯录文件:contact.dat
*/
    FILE *pf = fopen("/home/wdd/Desktop/c++_ws/Contacts/contact.dat", "r");
    PeoInfo tmp = {0};
    if (pf == NULL)
    {
        perror("open contact fail");
        exit(-1);
    }
    while (fread(&tmp, sizeof(PeoInfo), 1, pf)) //fread 以数据块的方式从文件中读取内容
    {
        check_capacity(p);
        p->data[p->sz++] = tmp;
    }
    fclose(pf);
    pf = NULL;
};
void AddContact(pContact p)
{
    //检查通讯录容量
    check_capacity(p);

    printf("请输入联系人姓名：");
    scanf("%s", p->data[p->sz].name);
    printf("请输入联系人性别：");
    scanf("%s", p->data[p->sz].sex);
    printf("请输入联系人电话：");
    scanf("%s", p->data[p->sz].tele);
    printf("请输入联系人地址：");
    scanf("%s", p->data[p->sz].addr);
    printf("请输入联系人年龄：");
    scanf("%d", &(p->data[p->sz].age));
    p->sz++;
    printf("添加成功\n");
    SaveContact(p);
    return;
};
static int FindEntry(char *c, pContact p)
{
    /*
        如果把函数声明为static类型，则该函数名除了对该函数声明的文件可见外，
        其他文件都无法访问。也就是只能被本文件中的函数调用，而不能被同一程序中的其他文件的函数调用。

        在查找联系人时，如果用户输入的联系人的姓名存在，则返回该地址
        int strcmp(const char *s1, const char *s2);
        功能：比较 s1 和 s2 的大小，比较的是字符ASCII码大小。
        参数：
            s1：字符串1首地址
            s2：字符串2首地址
        返回值：
            相等：0
            大于：>0 在不同操作系统strcmp结果会不同   返回ASCII差值
            小于：<0
    */
    int i = 0;
    for (i = 0; i < p->sz; i++)
    {
        if (strcmp(c, p->data[i].name) == 0)
        {
            return i;
        }
    }
    return -1;
}
void DelContact(pContact p)

{
    //删除指定联系人
    char name[NAME_MAX];
    int index;
    printf("请输入想要删除联系人的姓名：");
    scanf("%s", name);
    getchar();
    index = FindEntry(name, p);
    if (index == -1)
    {
        printf("想要删除的联系人不存在\n");
        return;
    }
    else
    {
        for (int i = index; i < p->sz - 1; i++)
        {
            p->data[i] = p->data[i + 1];
        }
        p->sz--;
        //清除最后一个数据
        PeoInfo *tmp = realloc(p->data, (p->capacity - 1) * sizeof(PeoInfo));
        if (tmp != NULL)
        {
            p->data = tmp;
            p->capacity - 1;
        }

        printf("删除成功\n");
    }
    SaveContact(p);
    return;
};
void ModifyContact(pContact p)
{
    int index;
    char name[NAME_MAX];
    printf("请输入需要修改的联系人的姓名：\n");
    scanf("%s", name);
    getchar();
    index = FindEntry(name, p);
    if (index == -1)
    {
        printf("通讯录中没有此联系人！\n");
        return;
    }
    else
    {
        printf("\n\t\tContact\n");
        printf("%5s\t%s\t%2s\t%5s\t%5s\t\n",
               "name", "age", "sex", "addr", "tele");
        printf("%5s\t%d\t%3s\t%5s\t%5s\t\n",
               p->data[index].name,
               p->data[index].age,
               p->data[index].sex,
               p->data[index].addr,
               p->data[index].tele);

        printf("修改姓名为：\n");
        scanf("%s", p->data[index].name);
        printf("修改性别为：\n");
        scanf("%s", p->data[index].sex);
        printf("修改年龄为：\n");
        scanf("%d", &(p->data[index].age));
        printf("修改电话号码为：\n");
        scanf("%s", p->data[index].tele);
        printf("修改地址为：\n");
        scanf("%s", p->data[index].addr);
        printf("修改完成\n");
    }
    return;
};
void SearchContact(pContact p)
{
    int index;
    char name[NAME_MAX];
    printf("需要搜索的姓名：\n");
    scanf("%s", name);
    getchar();
    index = FindEntry(name, p);
    if (index == -1)
    {
        printf("通讯录中没有此联系人！\n");
        return;
    }
    else
    {
        printf("\n\t\tContact\n");
        printf("%5s\t%s\t%2s\t%5s\t%5s\t\n",
               "name", "age", "sex", "addr", "tele");
        printf("%5s\t%d\t%3s\t%5s\t%5s\t\n",
               p->data[index].name,
               p->data[index].age,
               p->data[index].sex,
               p->data[index].addr,
               p->data[index].tele);
    }
    return;
};
void printPeo(PeoInfo *p)
{
    printf("\t%s\n", p->name);
    printf("\t%s\n", p->sex);
    printf("\t%d\n", p->age);
    printf("\t%s\n", p->tele);
    printf("\t%s\n", p->addr);
}
void ShowContact(pContact p)
{
    if (p->sz == 0)
    {
        printf("您的通讯录中没有联系人，请先添加：\n");
    }
    else
    {
        printf("\n\t\tContact\n");
        printf("%5s\t%s\t%2s\t%5s\t%5s\t\n",
               "name", "age", "sex", "addr", "tele");
        for (int i = 0; i < p->sz; i++)
        {
            printf("%5s\t%d\t%3s\t%5s\t%5s\t\n",
                   p->data[i].name,
                   p->data[i].age,
                   p->data[i].sex,
                   p->data[i].addr,
                   p->data[i].tele);
        }
    }
    return;
};
void SortContact(pContact p)
{
    int min_index = 0;
    int res;
    for (int i = 0; i < p->sz; i++)
    {
        for (int j = i + 1; j < p->sz; j++)
        {
            res = strcmp(p->data[i].name, p->data[j].name);
            if (res > 0)
            {
                char temp[NAME_MAX];
                strcpy(temp, p->data[i].name);
                strcpy(p->data[i].name, p->data[j].name);
                strcpy(p->data[j].name, temp);
            }
        }
    }
    return;
}
void EmptyContact(pContact p)
{
    p->sz = 0;
    if (p->sz == 0)
    {
        free(p->data);
        p->capacity = 0;
        p->data = NULL;
        printf("通讯录已清空\n");
    }
};
void SaveContact(pContact p)
{
    FILE *pf = fopen("/home/wdd/Desktop/c++_ws/Contacts/contact.dat", "w+");
    if (pf == NULL)
    {
        perror("open contact fail");
        exit(-1);
    }
    for (int i = 0; i < p->sz; i++)
    {
        fwrite(&(p->data[i]), sizeof(PeoInfo), 1, pf);
    }
    fclose(pf);
    pf = NULL;
    SortContact(p);
    printf("保存成功\n");
    return;
};
void DestroyContact(pContact p)
{
    free(p->data);
    p->capacity = 0;
    p->data = NULL;
    p->sz = 0;
};
int Exit_()
{
    printf("确认退出通讯录吗？(Yes/No)\n");
    char Yes[5] = "Yes";
    char No[5] = "No";
    char flag[5];
    scanf("%s", flag);
    // getchar();
    if (strcmp(flag, Yes) == 0)
    {
        return 0;
    }
    return 1;
}